<template>
  <div class="scanner-container">
    <div v-show="!isLoading">
      <video poster="data:image/gif,AAAA" ref="scanner"></video>
      <div class="overlay-element"></div>
      <div class="laser"></div>
    </div>
    <audio id="scanAudioTip" controls="controls" hidden :src="audioTip" ref="audio"></audio>
  </div>
</template>
      
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { BrowserMultiFormatReader, Exception } from "@zxing/library"

// 定义 props
const props = defineProps({
  width: String,
  height: String
})

// 定义 emits
const emit = defineEmits(['decode', 'loaded'])

// 响应式数据
const audioTip = ref(new URL('@/assets/media/tishi.mp3', import.meta.url).href)
const isLoading = ref(true)
const scanner = ref(null)
const audio = ref(null)
const codeReader = new BrowserMultiFormatReader()
let videoStream = null // 用于存储视频流

// 检查浏览器支持
const isMediaStreamAPISupported = navigator && 
  navigator.mediaDevices && 
  'enumerateDevices' in navigator.mediaDevices

// 方法
const start = async () => {
  try {
    // 获取并存储视频流
    videoStream = await codeReader.decodeFromVideoDevice(undefined, scanner.value, (result, err) => {
      if (result) {
        emit('decode', result.text)
        playTip()
      }
      if (err && !(err instanceof Exception)) {
        console.error('Decoding error:', err)
      }
    })
  } catch (err) {
    console.error('Failed to start scanner:', err)
    throw new Exception('Failed to start scanner')
  }
}

const playTip = async () => {
  try {
    if (!audio.value) return
    
    audio.value.currentTime = 0
    await audio.value.play().catch(e => {
      // 处理自动播放限制
      if (e.name === 'NotAllowedError') {
        console.warn('Audio playback blocked by browser policy')
      } else {
        console.error('Audio playback error:', e)
      }
    })
  } catch (e) {
    console.error('Audio play error:', e)
  }
}

// 停止摄像头方法
const stopCamera = () => {
  try {
    // 停止扫码器
    codeReader.reset()
    
    // 关闭视频流
    if (videoStream) {
      videoStream.getVideoTracks().forEach(track => {
        track.stop()
        track.enabled = false
      })
      videoStream = null
    }
    
    console.log('摄像头已关闭')
  } catch (error) {
    console.error('关闭摄像头失败:', error)
  }
}

// 暴露方法给父组件
defineExpose({
  stopCamera
})

// 生命周期钩子
onMounted(async () => {
  if (!isMediaStreamAPISupported) {
    throw new Exception('Media Stream API is not supported')
  }

  // 确保视频元素存在再设置事件
  if (scanner.value) {
    scanner.value.oncanplay = (event) => {
      isLoading.value = false
      emit('loaded')
    }
  }

  try {
    await start()
  } catch (err) {
    console.error('Scanner initialization failed:', err)
    isLoading.value = false
  }
})

onBeforeUnmount(() => {
  // 清理所有资源
  codeReader.reset()
  
  // 关闭视频流
  if (videoStream) {
    videoStream.getVideoTracks().forEach(track => track.stop())
  }
  
  // 清理音频
  if (audio.value) {
    audio.value.pause()
    audio.value.currentTime = 0
    audio.value.removeAttribute('src')
    audio.value.load()
  }
})
</script>

<style scoped>
video {
  max-width: 100%;
  max-height: 100%;
}
.scanner-container {
  position: relative;
}
.overlay-element {
  position: absolute;
  top: 0;
  width: 100%;
  height: 99%;
  background: rgba(30, 30, 30, 0.5);
  -webkit-clip-path: polygon(
    0% 0%,
    0% 100%,
    20% 100%,
    20% 20%,
    80% 20%,
    80% 80%,
    20% 80%,
    20% 100%,
    100% 100%,
    100% 0%
  );
  clip-path: polygon(
    0% 0%,
    0% 100%,
    20% 100%,
    20% 20%,
    80% 20%,
    80% 80%,
    20% 80%,
    20% 100%,
    100% 100%,
    100% 0%
  );
}
.laser {
  width: 60%;
  margin-left: 20%;
  background-color: tomato;
  height: 1px;
  position: absolute;
  top: 40%;
  z-index: 2;
  box-shadow: 0 0 4px red;
  -webkit-animation: scanning 2s infinite;
  animation: scanning 2s infinite;
}
@-webkit-keyframes scanning {
  50% {
    -webkit-transform: translateY(75px);
    transform: translateY(75px);
  }
}
@keyframes scanning {
  50% {
    -webkit-transform: translateY(75px);
    transform: translateY(75px);
  }
}
</style>